@@ -0,0 +1,77 @@ |
||
1 |
+module Agents |
|
2 |
+ class WitaiAgent < Agent |
|
3 |
+ cannot_be_scheduled! |
|
4 |
+ |
|
5 |
+ description <<-MD |
|
6 |
+ |
|
7 |
+ `wit.ai` agent receives events, sends text query to your `wit.ai` instance and generates outcome events. Fill in `Server Access Token` of your `wit.ai` instance. Use [Liquid](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) to fill query field. |
|
8 |
+ `expected_receive_period_in_days` is the expected number of days by which agent should receive events. It helps in determining if the agent is working. |
|
9 |
+ MD |
|
10 |
+ |
|
11 |
+ event_description <<-MD |
|
12 |
+ |
|
13 |
+ Every event have `outcomes` key with your payload as value. Sample event: |
|
14 |
+ |
|
15 |
+ {"outcome" : [ |
|
16 |
+ {"_text" : "set temperature to 34 degrees at 11 PM", |
|
17 |
+ "intent" : "get_temperature", |
|
18 |
+ "entities" : { |
|
19 |
+ "temperature" : [ |
|
20 |
+ { |
|
21 |
+ "type" : "value", |
|
22 |
+ "value" : 34, |
|
23 |
+ "unit" : "degree" |
|
24 |
+ }], |
|
25 |
+ "datetime" : [ |
|
26 |
+ { |
|
27 |
+ "grain" : "hour", |
|
28 |
+ "type" : "value", |
|
29 |
+ "value" : "2015-03-26T21:00:00.000-07:00" |
|
30 |
+ }]}, |
|
31 |
+ "confidence" : 0.556 |
|
32 |
+ }]} |
|
33 |
+ MD |
|
34 |
+ |
|
35 |
+ def default_options |
|
36 |
+ { |
|
37 |
+ 'server_access_token' => 'xxxxx', |
|
38 |
+ 'expected_receive_period_in_days' => 2, |
|
39 |
+ 'query' => '{{xxxx}}' |
|
40 |
+ } |
|
41 |
+ end |
|
42 |
+ |
|
43 |
+ def working? |
|
44 |
+ !recent_error_logs? && most_recent_event && event_created_within?(interpolated['expected_receive_period_in_days']) |
|
45 |
+ end |
|
46 |
+ |
|
47 |
+ def validate_options |
|
48 |
+ unless %w[server_access_token query expected_receive_period_in_days].all? { |field| options[field].present? } |
|
49 |
+ errors.add(:base, 'All fields are required') |
|
50 |
+ end |
|
51 |
+ end |
|
52 |
+ |
|
53 |
+ def receive(incoming_events) |
|
54 |
+ incoming_events.each do |event| |
|
55 |
+ interpolated_event = interpolated event |
|
56 |
+ response = HTTParty.get query_url(interpolated_event[:query]), headers |
|
57 |
+ create_event 'payload' => { |
|
58 |
+ 'outcomes' => JSON.parse(response.body)['outcomes'] |
|
59 |
+ } |
|
60 |
+ end |
|
61 |
+ end |
|
62 |
+ |
|
63 |
+ private |
|
64 |
+ def api_endpoint |
|
65 |
+ 'https://api.wit.ai/message?v=20141022&q=' |
|
66 |
+ end |
|
67 |
+ |
|
68 |
+ def query_url(query) |
|
69 |
+ api_endpoint + URI.encode(query) |
|
70 |
+ end |
|
71 |
+ |
|
72 |
+ def headers |
|
73 |
+ #oauth |
|
74 |
+ {:headers => {'Authorization' => 'Bearer ' + interpolated[:server_access_token]}} |
|
75 |
+ end |
|
76 |
+ end |
|
77 |
+end |
@@ -0,0 +1,27 @@ |
||
1 |
+{ |
|
2 |
+ "msg_id":"x", |
|
3 |
+ "_text":"x", |
|
4 |
+ "outcomes": [ |
|
5 |
+ { |
|
6 |
+ "_text": "set the temperature to 22 degrees at 7 PM", |
|
7 |
+ "intent": "get_temparature", |
|
8 |
+ "entities": { |
|
9 |
+ "datetime": [ |
|
10 |
+ { |
|
11 |
+ "grain": "hour", |
|
12 |
+ "type": "value", |
|
13 |
+ "value": "2015-03-27T21:00:00.000-07:00" |
|
14 |
+ } |
|
15 |
+ ], |
|
16 |
+ "temperature": [ |
|
17 |
+ { |
|
18 |
+ "type": "value", |
|
19 |
+ "value": 34, |
|
20 |
+ "unit": "degree" |
|
21 |
+ } |
|
22 |
+ ] |
|
23 |
+ }, |
|
24 |
+ "confidence": 0.554 |
|
25 |
+ } |
|
26 |
+ ] |
|
27 |
+} |
@@ -0,0 +1,71 @@ |
||
1 |
+require 'spec_helper' |
|
2 |
+ |
|
3 |
+describe Agents::WitaiAgent do |
|
4 |
+ before do |
|
5 |
+ stub_request(:get, /wit/).to_return(:body => File.read(Rails.root.join('spec/data_fixtures/witai.json')), :status => 200, :headers => {'Content-Type' => 'text/json'}) |
|
6 |
+ |
|
7 |
+ @valid_params = { |
|
8 |
+ :server_access_token => 'x', |
|
9 |
+ :expected_receive_period_in_days => '2', |
|
10 |
+ :query => '{{message.content}}' |
|
11 |
+ } |
|
12 |
+ |
|
13 |
+ @checker = Agents::WitaiAgent.new :name => 'wit.ai agent', |
|
14 |
+ :options => @valid_params |
|
15 |
+ |
|
16 |
+ @checker.user = users :jane |
|
17 |
+ @checker.save! |
|
18 |
+ |
|
19 |
+ @event = Event.new |
|
20 |
+ @event.agent = agents :jane_weather_agent |
|
21 |
+ @event.payload = {:message => { |
|
22 |
+ :content => 'set the temperature to 22 degrees at 7 PM' |
|
23 |
+ }} |
|
24 |
+ @event.save! |
|
25 |
+ end |
|
26 |
+ |
|
27 |
+ describe '#validation' do |
|
28 |
+ before do |
|
29 |
+ expect(@checker).to be_valid |
|
30 |
+ end |
|
31 |
+ |
|
32 |
+ it 'validates presence of server access token' do |
|
33 |
+ @checker.options[:server_access_token] = nil |
|
34 |
+ expect(@checker).not_to be_valid |
|
35 |
+ end |
|
36 |
+ |
|
37 |
+ it 'validates presence of query' do |
|
38 |
+ @checker.options[:query] = nil |
|
39 |
+ expect(@checker).not_to be_valid |
|
40 |
+ end |
|
41 |
+ |
|
42 |
+ it 'validates presence of expected receive period in days key' do |
|
43 |
+ @checker.options[:expected_receive_period_in_days] = nil |
|
44 |
+ expect(@checker).not_to be_valid |
|
45 |
+ end |
|
46 |
+ end |
|
47 |
+ |
|
48 |
+ describe '#working' do |
|
49 |
+ it 'checks if agent is working when event is received withing expected number of days' do |
|
50 |
+ expect(@checker).not_to be_working |
|
51 |
+ Agents::WitaiAgent.async_receive @checker.id, [@event.id] |
|
52 |
+ expect(@checker.reload).to be_working |
|
53 |
+ two_days_from_now = 2.days.from_now |
|
54 |
+ stub(Time).now { two_days_from_now } |
|
55 |
+ expect(@checker.reload).not_to be_working |
|
56 |
+ end |
|
57 |
+ end |
|
58 |
+ |
|
59 |
+ describe '#receive' do |
|
60 |
+ it 'checks that a new event is created after receiving one' do |
|
61 |
+ expect { |
|
62 |
+ @checker.receive([@event]) |
|
63 |
+ }.to change { Event.count }.by(1) |
|
64 |
+ end |
|
65 |
+ |
|
66 |
+ it 'checks the integrity of new event' do |
|
67 |
+ @checker.receive([@event]) |
|
68 |
+ expect(Event.last.payload[:outcomes][0][:_text]).to eq(@event.payload[:message][:content]) |
|
69 |
+ end |
|
70 |
+ end |
|
71 |
+end |